package cbcrypt

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"encoding/hex"
	"fmt"
)

// @PS 下面这段代码主题来自网路哦

func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	//Repeat()函数的功能是把切片[]byte{byte(padding)}复制padding个，然后合并成新的字节切片返回
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padText...)
}

//填充的反向操作，删除填充字符串
func PKCS7UnPadding(origData []byte) ([]byte, error) {
	//获取数据长度
	length := len(origData)
	if length == 0 {
		return nil, fmt.Errorf("加密字符串错误！")
	} else {
		//获取填充字符串长度
		unPadding := int(origData[length-1])
		//截取切片，删除填充字节，并且返回明文
		return origData[:(length - unPadding)], nil
	}
}

// 实现加密
func AesEncrypt(origData []byte, key string) string {
	byteKey := []byte(key)

	// 创建加密算法实例
	block, err := aes.NewCipher(byteKey)
	if err != nil {
		panic(err.Error())
	}

	// 获取块的大小
	blockSize := block.BlockSize()

	// 对数据进行填充，让数据长度满足需求
	origData = PKCS7Padding(origData, blockSize)

	// 采用AES加密方法中CBC加密模式
	blocMode := cipher.NewCBCEncrypter(block, byteKey[:blockSize])
	crypted := make([]byte, len(origData))

	// 执行加密
	blocMode.CryptBlocks(crypted, origData)

	return hex.EncodeToString(crypted)
}

// 实现解密
func AesDeCrypt(crypted []byte, key string) string {
	byteKey := []byte(key)
	// 创建加密算法实例
	block, err := aes.NewCipher(byteKey)
	if err != nil {
		panic(err.Error())
	}

	// 获取块大小
	blockSize := block.BlockSize()

	// 创建加密客户端实例
	blockMode := cipher.NewCBCDecrypter(block, byteKey[:blockSize])
	origData := make([]byte, len(crypted))

	// 这个函数也可以用来解密
	blockMode.CryptBlocks(origData, crypted)

	// 去除填充字符串
	origData, err = PKCS7UnPadding(origData)
	if err != nil {
		panic(err.Error())
	}

	return base64.StdEncoding.EncodeToString(origData)
}
